green <- miscgis::miscgis_pals$tableau_cat[["green"]]
blue <- miscgis::miscgis_pals$tableau_cat[["blue"]]
orange <- miscgis::miscgis_pals$tableau_cat[["orange"]]
red <- miscgis::miscgis_pals$tableau_cat[["red"]]
teal <- miscgis::miscgis_pals$tableau_cat[["teal"]]
pal_rgb_4 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue")] %>% unlist %>% palette()
pal_rgb_4 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue")] %>% unlist %>% palette()
pal_rgb_6 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue","orange","purple")] %>% unlist %>% palette()
pal_rgb_6 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue","orange","purple")] %>% unlist %>% palette()
Seattle Boundary
if(!file.exists(root_file('1-data/4-interim/seattle-sf.rds'))){
tigris::places(state = "WA") %>%
tigris::filter_place(place = "Seattle") %>%
spTransform(CRSobj = crs_proj) %>%
st_as_sf() %>%
miscgis::coerce_to_geom(sf::st_multipolygon) %>%
write_rds(root_file('1-data/4-interim/seattle-sf.rds'))
}
sea_sf <- read_rds(root_file('1-data/4-interim/seattle-sf.rds'))
green <- miscgis::miscgis_pals$tableau_cat[["green"]]
myLfltGrey(data = as(sea_sf,'Spatial')) %>% addPolygons(color = green,opacity = 1,fillColor = green,fillOpacity = .5)
King County Subdivision Boundary
if(!file.exists(root_file('1-data/4-interim/seattle-ccd-sf.rds'))){
tigris::county_subdivisions(state = "53",county = "033") %>%
subset(NAME == "Seattle") %>%
spTransform(CRSobj = crs_proj) %>%
st_as_sf() %>%
miscgis::coerce_to_geom(sf::st_multipolygon) %>%
write_rds(root_file('1-data/4-interim/seattle-ccd-sf.rds'))
}
sea_ccd_sf <- read_rds(root_file('1-data/4-interim/seattle-ccd-sf.rds'))
myLfltGrey(data = as(sea_ccd_sf,'Spatial')) %>% addPolygons(color = blue,opacity = 1,fillColor = blue,fillOpacity = .5)
Tracts in King County
Although this assessment is primarily focused on three communities within the Seattle CCD subdivision of King County, one of the indicators (housing market conditions) uses neighboring tracts to determine displacement risk. Some of the neighboring tracts are part of other county subdivision, but rather than targeting just those specific tracts, this method collects data for all King County tracts and then runs the analysis on the appropriate subsets.
In the absence of a straight-forward method for identifying all the census tracts in the Seattle CCD subdivision of King County, it is possible to extract this information from American Factfinder. This tutorial describes how to use the American Factfinder interface to extract a list of all “all tracts within (or partially within) a census place”; substituting “county subdivision” for “place” will retrieve the desired results.
if(!file.exists(root_file('1-data/4-interim/tr-kc-wtr-sf.rds'))){
# All KC tracts
tr_kc_wtr_sf <-
tigris::tracts(state = '53',county = '033', year = 2014) %>%
spTransform(CRSobj = crs_proj) %>%
st_as_sf() %>%
miscgis::coerce_to_geom(sf::st_multipolygon)
# Seattle CCD tracts
# Note: because this selection includes all tracts "within or partially-within" the Seattle CC,
# several tract GEOIDs are duplicated in the selection. For the sake of clarity, these duplicates
# are removed from the final vector of GEOIDs.
tr_ccd_geoid <-
read_csv(
root_file('1-data/3-external/manual/seattle-ccd/ACS_12_5YR_B01001/ACS_12_5YR_B01001_with_ann.csv'),
col_types = cols(Id2 = col_character()),
skip = 1) %>%
mutate(NEW_GEOID1 = str_sub(Id2,1,5),
NEW_GEOID2 = str_sub(Id2,16,21),
GEOID = paste0(NEW_GEOID1,NEW_GEOID2),
UNIQUE = !duplicated(GEOID)) %>%
filter(UNIQUE) %>%
select(GEOID) %>% unlist(use.names = F)
# Create a county Seattle CCD subdivision column and save
tr_kc_wtr_sf %>%
mutate(SEACCD_LGL = ifelse(GEOID %in% tr_ccd_geoid,TRUE,FALSE)) %>%
write_rds(root_file('1-data/4-interim/tr-kc-wtr-sf.rds'))
}
tr_kc_wtr_sf <- read_rds(root_file('1-data/4-interim/tr-kc-wtr-sf.rds'))
show_tr_ccd_wtr_sf <- function(){
seaccd <- tr_kc_wtr_sf %>% filter(SEACCD_LGL)
other_kc <- tr_kc_wtr_sf %>% filter(!SEACCD_LGL)
myLfltGrey() %>%
addPolygons(data = as(seaccd,"Spatial"),weight = .5,color = blue,opacity = 1,fillColor = blue,fillOpacity = .5) %>%
addPolygons(data = as(other_kc,"Spatial"),weight = .5,color = orange,opacity = 1,fillColor = orange,fillOpacity = .5)
}
show_tr_ccd_wtr_sf()
Puget Sound Waterbodies
These are useful for “clipping” census geographies whose boundaries extend into waterbodies.
if(!file.exists(root_file('1-data/4-interim/wtr-sf.rds'))){
fp_wtr <- root_file('1-data/3-external/NHDMajor.gdb')
# check if the file already exists, if not then download it
if(!file.exists(fp_wtr)){
url <- "ftp://www.ecy.wa.gov/gis_a/inlandWaters/NHD/NHDmajor.gdb.zip" # save the URL for the waterbodies data
temp <- tempfile() # create a temporary file to hold the compressed download
download(url, dest = temp, mode="wb") # download the file
unzip (temp, exdir = root_file('1-data/3-external/')) # extract the ESRI geodatabase file to a project folder
}
wtr_sp <-
suppressWarnings(readOGR(dsn = fp_wtr, # create a waterbodies shape
layer = "NHD_MajorWaterbodies",verbose = FALSE,pointDropZ = TRUE)) %>%
gBuffer(byid=TRUE, width=0) %>% # clean up self-intersecting polygons
spTransform(CRSobj = crs_proj) # transform the projection to match the project projection
wtr_sf <-
wtr_sp %>%
st_as_sf() %>%
miscgis::coerce_to_geom(st_multipolygon)
wtr_sf %>%
st_intersects(x = sea_ccd_sf,y = .) %>%
unlist(use.names = F) %>%
wtr_sf[.,] %>%
write_rds(root_file('1-data/4-interim/wtr-sf.rds'))
}
wtr_sf <- read_rds(root_file('1-data/4-interim/wtr-sf.rds'))
show_wtr <- function(){
myLfltGrey(data = as(wtr_sf,'Spatial')) %>%
addPolygons(color = blue, opacity = 1,
weight = .5, fillColor = blue,fillOpacity = .5)
}
show_wtr()
KC Tracts Without (Western) Waterbodies
if(!file.exists(root_file('1-data/4-interim/tr-kc-sf.rds'))){
tr_kc_wtr_sf %>%
filter(TRACTCE %!in% '990100') %>% # remove the Puget Sound tract
mutate(geometry = st_difference(geometry,st_union(wtr_sf))) %>%
coerce_to_geom(st_multipolygon) %>%
write_rds(root_file('1-data/4-interim/tr-kc-sf.rds'))
}
tr_kc_sf <- read_rds(root_file('1-data/4-interim/tr-kc-sf.rds'))
show_tr_kc_sf <- function(){
seaccd <- tr_kc_sf %>% filter(SEACCD_LGL)
other_kc <- tr_kc_sf %>% filter(!SEACCD_LGL)
myLfltGrey() %>%
addPolygons(data = as(seaccd,"Spatial"),weight = .5,color = blue,opacity = 1,fillColor = blue,fillOpacity = .5) %>%
addPolygons(data = as(other_kc,"Spatial"),weight = .5,color = orange,opacity = 1,fillColor = orange,fillOpacity = .5)
}
show_tr_kc_sf()
LS0tCmRmX3ByaW50OiB0aWJibGUKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICBwZGZfZG9jdW1lbnQ6CiAgICBrZWVwX3RleDogeWVzCmFsd2F5c19hbGxvd19odG1sOiB5ZXMKLS0tCgpgYGB7ciBtaXNjLXNldHVwLCBlY2hvID0gRkFMU0UsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxjb21tZW50PUZBTFNFfQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KG9wZXJhdG9yLnRvb2xzKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHJwcm9qcm9vdCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoc3ApCmxpYnJhcnkocmdlb3MpCmxpYnJhcnkobWlzY2dpcykKbGlicmFyeSh0aWdyaXMpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGRvd25sb2FkZXIpCmxpYnJhcnkobWlzY2dpcykKbGlicmFyeShzZikKcm9vdCA8LSBycHJvanJvb3Q6OmlzX3JzdHVkaW9fcHJvamVjdApyb290X2ZpbGUgPC0gcm9vdCRtYWtlX2ZpeF9maWxlKCkKYGBgCgpgYGB7ciBtaXNjLWNvbG9yc30KZ3JlZW4gPC0gbWlzY2dpczo6bWlzY2dpc19wYWxzJHRhYmxlYXVfY2F0W1siZ3JlZW4iXV0KYmx1ZSA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbWyJibHVlIl1dCm9yYW5nZSA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbWyJvcmFuZ2UiXV0KcmVkIDwtIG1pc2NnaXM6Om1pc2NnaXNfcGFscyR0YWJsZWF1X2NhdFtbInJlZCJdXQp0ZWFsIDwtIG1pc2NnaXM6Om1pc2NnaXNfcGFscyR0YWJsZWF1X2NhdFtbInRlYWwiXV0KcGFsX3JnYl80IDwtIG1pc2NnaXM6Om1pc2NnaXNfcGFscyR0YWJsZWF1X2NhdFtjKCJyZWQiLCJnb2xkIiwiZ3JlZW4iLCJibHVlIildICU+JSB1bmxpc3QgJT4lIHBhbGV0dGUoKQpwYWxfcmdiXzQgPC0gbWlzY2dpczo6bWlzY2dpc19wYWxzJHRhYmxlYXVfY2F0W2MoInJlZCIsImdvbGQiLCJncmVlbiIsImJsdWUiKV0gJT4lIHVubGlzdCAlPiUgcGFsZXR0ZSgpCnBhbF9yZ2JfNiA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbYygicmVkIiwiZ29sZCIsImdyZWVuIiwiYmx1ZSIsIm9yYW5nZSIsInB1cnBsZSIpXSAlPiUgdW5saXN0ICU+JSBwYWxldHRlKCkKcGFsX3JnYl82IDwtIG1pc2NnaXM6Om1pc2NnaXNfcGFscyR0YWJsZWF1X2NhdFtjKCJyZWQiLCJnb2xkIiwiZ3JlZW4iLCJibHVlIiwib3JhbmdlIiwicHVycGxlIildICU+JSB1bmxpc3QgJT4lIHBhbGV0dGUoKQpgYGAKCiMjI1NlYXR0bGUgQm91bmRhcnkKCmBgYHtyIG1pc2Mtc2VhLWJvdW5kLCBmaWcuY2FwPSJTZWF0dGxlXCdzIGdlb2dyYXBoaWMgYm91bmRhcnkifQoKaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLXNmLnJkcycpKSl7CiAgICAgICAgdGlncmlzOjpwbGFjZXMoc3RhdGUgPSAiV0EiKSAlPiUKICAgICAgICAgICAgICAgIHRpZ3Jpczo6ZmlsdGVyX3BsYWNlKHBsYWNlID0gIlNlYXR0bGUiKSAlPiUKICAgICAgICAgICAgICAgIHNwVHJhbnNmb3JtKENSU29iaiA9IGNyc19wcm9qKSAlPiUgCiAgICAgICAgICAgICAgICBzdF9hc19zZigpICU+JSAKICAgICAgICAgICAgICAgIG1pc2NnaXM6OmNvZXJjZV90b19nZW9tKHNmOjpzdF9tdWx0aXBvbHlnb24pICU+JSAKICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vc2VhdHRsZS1zZi5yZHMnKSkKICAgICAgICAKfQoKc2VhX3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLXNmLnJkcycpKQoKZ3JlZW4gPC0gbWlzY2dpczo6bWlzY2dpc19wYWxzJHRhYmxlYXVfY2F0W1siZ3JlZW4iXV0KCm15TGZsdEdyZXkoZGF0YSA9IGFzKHNlYV9zZiwnU3BhdGlhbCcpKSAlPiUgYWRkUG9seWdvbnMoY29sb3IgPSBncmVlbixvcGFjaXR5ID0gMSxmaWxsQ29sb3IgPSBncmVlbixmaWxsT3BhY2l0eSA9IC41KQoKYGBgCgojIyNLaW5nIENvdW50eSBTdWJkaXZpc2lvbiBCb3VuZGFyeQoKYGBge3IgbWlzYy1zZWEtY2NkLCBmaWcuY2FwPSJTZWF0dGxlIFN1YmRpdmlzaW9uIG9mIEtpbmcgQ291bnR5XCdzIGdlb2dyYXBoaWMgYm91bmRhcnkifQoKaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLWNjZC1zZi5yZHMnKSkpewogICAgICAgIHRpZ3Jpczo6Y291bnR5X3N1YmRpdmlzaW9ucyhzdGF0ZSA9ICI1MyIsY291bnR5ID0gIjAzMyIpICU+JSAKICAgICAgICAgICAgICAgIHN1YnNldChOQU1FID09ICJTZWF0dGxlIikgJT4lIAogICAgICAgICAgICAgICAgc3BUcmFuc2Zvcm0oQ1JTb2JqID0gY3JzX3Byb2opICU+JSAKICAgICAgICAgICAgICAgIHN0X2FzX3NmKCkgJT4lIAogICAgICAgICAgICAgICAgbWlzY2dpczo6Y29lcmNlX3RvX2dlb20oc2Y6OnN0X211bHRpcG9seWdvbikgJT4lIAogICAgICAgICAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLWNjZC1zZi5yZHMnKSkKfQoKc2VhX2NjZF9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vc2VhdHRsZS1jY2Qtc2YucmRzJykpCgpteUxmbHRHcmV5KGRhdGEgPSBhcyhzZWFfY2NkX3NmLCdTcGF0aWFsJykpICU+JSBhZGRQb2x5Z29ucyhjb2xvciA9IGJsdWUsb3BhY2l0eSA9IDEsZmlsbENvbG9yID0gYmx1ZSxmaWxsT3BhY2l0eSA9IC41KQoKYGBgCgojIyMgVHJhY3RzIGluIEtpbmcgQ291bnR5CkFsdGhvdWdoIHRoaXMgYXNzZXNzbWVudCBpcyBwcmltYXJpbHkgZm9jdXNlZCBvbiB0aHJlZSBjb21tdW5pdGllcyB3aXRoaW4gdGhlIFNlYXR0bGUgQ0NEIHN1YmRpdmlzaW9uIG9mIEtpbmcgQ291bnR5LCBvbmUgb2YgdGhlIGluZGljYXRvcnMgKGhvdXNpbmcgbWFya2V0IGNvbmRpdGlvbnMpIHVzZXMgbmVpZ2hib3JpbmcgdHJhY3RzIHRvIGRldGVybWluZSBkaXNwbGFjZW1lbnQgcmlzay4gU29tZSBvZiB0aGUgbmVpZ2hib3JpbmcgdHJhY3RzIGFyZSBwYXJ0IG9mIG90aGVyIGNvdW50eSBzdWJkaXZpc2lvbiwgYnV0IHJhdGhlciB0aGFuIHRhcmdldGluZyBqdXN0IHRob3NlIHNwZWNpZmljIHRyYWN0cywgdGhpcyBtZXRob2QgY29sbGVjdHMgZGF0YSBmb3IgYWxsIEtpbmcgQ291bnR5IHRyYWN0cyBhbmQgdGhlbiBydW5zIHRoZSBhbmFseXNpcyBvbiB0aGUgYXBwcm9wcmlhdGUgc3Vic2V0cy4KCkluIHRoZSBhYnNlbmNlIG9mIGEgc3RyYWlnaHQtZm9yd2FyZCBtZXRob2QgZm9yIGlkZW50aWZ5aW5nIGFsbCB0aGUgY2Vuc3VzIHRyYWN0cyBpbiB0aGUgU2VhdHRsZSBDQ0Qgc3ViZGl2aXNpb24gb2YgS2luZyBDb3VudHksIGl0IGlzIHBvc3NpYmxlIHRvIGV4dHJhY3QgdGhpcyBpbmZvcm1hdGlvbiBmcm9tIFtBbWVyaWNhbiBGYWN0ZmluZGVyXShodHRwczovL2ZhY3RmaW5kZXIuY2Vuc3VzLmdvdi9mYWNlcy9uYXYvanNmL3BhZ2VzL2luZGV4LnhodG1sKS4gVGhpcyBbdHV0b3JpYWxdKGh0dHBzOi8vYXNrLmNlbnN1cy5nb3YvZmFxLnBocD9pZD01MDAwJmZhcUlkPTE2MDUpIGRlc2NyaWJlcyBob3cgdG8gdXNlIHRoZSBBbWVyaWNhbiBGYWN0ZmluZGVyIGludGVyZmFjZSB0byBleHRyYWN0IGEgbGlzdCBvZiBhbGwgImFsbCB0cmFjdHMgd2l0aGluIChvciBwYXJ0aWFsbHkgd2l0aGluKSBhIGNlbnN1cyBwbGFjZSI7IHN1YnN0aXR1dGluZyAiY291bnR5IHN1YmRpdmlzaW9uIiBmb3IgInBsYWNlIiB3aWxsIHJldHJpZXZlIHRoZSBkZXNpcmVkIHJlc3VsdHMuCgpgYGB7ciBtaXNjLXRyLWtjLXd0cn0KCmlmKCFmaWxlLmV4aXN0cyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2Mtd3RyLXNmLnJkcycpKSl7CiAgICAgICAgCiAgICAgICAgIyBBbGwgS0MgdHJhY3RzCiAgICAgICAgdHJfa2Nfd3RyX3NmIDwtCiAgICAgICAgICAgICAgICB0aWdyaXM6OnRyYWN0cyhzdGF0ZSA9ICc1MycsY291bnR5ID0gJzAzMycsIHllYXIgPSAyMDE0KSAlPiUKICAgICAgICAgICAgICAgIHNwVHJhbnNmb3JtKENSU29iaiA9IGNyc19wcm9qKSAlPiUgCiAgICAgICAgICAgICAgICBzdF9hc19zZigpICU+JSAKICAgICAgICAgICAgICAgIG1pc2NnaXM6OmNvZXJjZV90b19nZW9tKHNmOjpzdF9tdWx0aXBvbHlnb24pIAogICAgICAgCiAgICAgICAgICMgU2VhdHRsZSBDQ0QgdHJhY3RzIAogICAgICAgICAjIE5vdGU6IGJlY2F1c2UgdGhpcyBzZWxlY3Rpb24gaW5jbHVkZXMgYWxsIHRyYWN0cyAid2l0aGluIG9yIHBhcnRpYWxseS13aXRoaW4iIHRoZSBTZWF0dGxlIENDLAogICAgICAgICAjIHNldmVyYWwgdHJhY3QgR0VPSURzIGFyZSBkdXBsaWNhdGVkIGluIHRoZSBzZWxlY3Rpb24uIEZvciB0aGUgc2FrZSBvZiBjbGFyaXR5LCB0aGVzZSBkdXBsaWNhdGVzCiAgICAgICAgICMgYXJlIHJlbW92ZWQgZnJvbSB0aGUgZmluYWwgdmVjdG9yIG9mIEdFT0lEcy4KICAgICAgICB0cl9jY2RfZ2VvaWQgPC0gCiAgICAgICAgICAgICAgICByZWFkX2NzdigKICAgICAgICAgICAgICAgICAgICAgICAgcm9vdF9maWxlKCcxLWRhdGEvMy1leHRlcm5hbC9tYW51YWwvc2VhdHRsZS1jY2QvQUNTXzEyXzVZUl9CMDEwMDEvQUNTXzEyXzVZUl9CMDEwMDFfd2l0aF9hbm4uY3N2JyksIAogICAgICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKElkMiA9IGNvbF9jaGFyYWN0ZXIoKSksIAogICAgICAgICAgICAgICAgICAgICAgICBza2lwID0gMSkgJT4lIAogICAgICAgICAgICAgICAgbXV0YXRlKE5FV19HRU9JRDEgPSBzdHJfc3ViKElkMiwxLDUpLAogICAgICAgICAgICAgICAgICAgICAgIE5FV19HRU9JRDIgPSBzdHJfc3ViKElkMiwxNiwyMSksCiAgICAgICAgICAgICAgICAgICAgICAgR0VPSUQgPSBwYXN0ZTAoTkVXX0dFT0lEMSxORVdfR0VPSUQyKSwKICAgICAgICAgICAgICAgICAgICAgICBVTklRVUUgPSAhZHVwbGljYXRlZChHRU9JRCkpICU+JQogICAgICAgICAgICAgICAgZmlsdGVyKFVOSVFVRSkgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KEdFT0lEKSAlPiUgdW5saXN0KHVzZS5uYW1lcyA9IEYpCiAgICAgICAgCiAgICAgICAgIyBDcmVhdGUgYSBjb3VudHkgU2VhdHRsZSBDQ0Qgc3ViZGl2aXNpb24gY29sdW1uIGFuZCBzYXZlCgogICAgICAgIHRyX2tjX3d0cl9zZiAlPiUgCiAgICAgICAgICAgICAgICBtdXRhdGUoU0VBQ0NEX0xHTCA9IGlmZWxzZShHRU9JRCAlaW4lIHRyX2NjZF9nZW9pZCxUUlVFLEZBTFNFKSkgJT4lIAogICAgICAgICAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS90ci1rYy13dHItc2YucmRzJykpCn0KCnRyX2tjX3d0cl9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2Mtd3RyLXNmLnJkcycpKQoKc2hvd190cl9jY2Rfd3RyX3NmIDwtIGZ1bmN0aW9uKCl7CiAgICAgICAgCiAgICAgICAgc2VhY2NkIDwtIHRyX2tjX3d0cl9zZiAlPiUgZmlsdGVyKFNFQUNDRF9MR0wpCiAgICAgICAgb3RoZXJfa2MgPC0gdHJfa2Nfd3RyX3NmICU+JSBmaWx0ZXIoIVNFQUNDRF9MR0wpCiAgICAgICAgCiAgICAgICAgbXlMZmx0R3JleSgpICU+JSAKICAgICAgICBhZGRQb2x5Z29ucyhkYXRhID0gYXMoc2VhY2NkLCJTcGF0aWFsIiksd2VpZ2h0ID0gLjUsY29sb3IgPSBibHVlLG9wYWNpdHkgPSAxLGZpbGxDb2xvciA9IGJsdWUsZmlsbE9wYWNpdHkgPSAuNSkgJT4lIAogICAgICAgIGFkZFBvbHlnb25zKGRhdGEgPSBhcyhvdGhlcl9rYywiU3BhdGlhbCIpLHdlaWdodCA9IC41LGNvbG9yID0gb3JhbmdlLG9wYWNpdHkgPSAxLGZpbGxDb2xvciA9IG9yYW5nZSxmaWxsT3BhY2l0eSA9IC41KQp9CgpzaG93X3RyX2NjZF93dHJfc2YoKQoKCmBgYAoKIyMjUHVnZXQgU291bmQgV2F0ZXJib2RpZXMKClRoZXNlIGFyZSB1c2VmdWwgZm9yICJjbGlwcGluZyIgY2Vuc3VzIGdlb2dyYXBoaWVzIHdob3NlIGJvdW5kYXJpZXMgZXh0ZW5kIGludG8gd2F0ZXJib2RpZXMuCgpgYGB7ciBtaXNjLXd0ciwgZmlnLmNhcD0iUHVnZXQgU291bmQgd2F0ZXJib2RpZXMifQoKaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS93dHItc2YucmRzJykpKXsKICAgICAgICBmcF93dHIgPC0gcm9vdF9maWxlKCcxLWRhdGEvMy1leHRlcm5hbC9OSERNYWpvci5nZGInKQoKIyBjaGVjayBpZiB0aGUgZmlsZSBhbHJlYWR5IGV4aXN0cywgaWYgbm90IHRoZW4gZG93bmxvYWQgaXQKaWYoIWZpbGUuZXhpc3RzKGZwX3d0cikpewogICAgICAgIAogICAgICAgIHVybCA8LSAiZnRwOi8vd3d3LmVjeS53YS5nb3YvZ2lzX2EvaW5sYW5kV2F0ZXJzL05IRC9OSERtYWpvci5nZGIuemlwIiAjIHNhdmUgdGhlIFVSTCBmb3IgdGhlIHdhdGVyYm9kaWVzIGRhdGEKICAgICAgICAKICAgICAgICB0ZW1wIDwtIHRlbXBmaWxlKCkgIyBjcmVhdGUgYSB0ZW1wb3JhcnkgZmlsZSB0byBob2xkIHRoZSBjb21wcmVzc2VkIGRvd25sb2FkCiAgICAgICAgCiAgICAgICAgZG93bmxvYWQodXJsLCBkZXN0ID0gdGVtcCwgbW9kZT0id2IiKSAjIGRvd25sb2FkIHRoZSBmaWxlCiAgICAgICAgCiAgICAgICAgdW56aXAgKHRlbXAsIGV4ZGlyID0gcm9vdF9maWxlKCcxLWRhdGEvMy1leHRlcm5hbC8nKSkgIyBleHRyYWN0IHRoZSBFU1JJIGdlb2RhdGFiYXNlIGZpbGUgdG8gYSBwcm9qZWN0IGZvbGRlcgp9Cgp3dHJfc3AgPC0KICAgICAgICBzdXBwcmVzc1dhcm5pbmdzKHJlYWRPR1IoZHNuID0gZnBfd3RyLCAgICAgICMgY3JlYXRlIGEgd2F0ZXJib2RpZXMgc2hhcGUKICAgICAgICAgICAgICAgIGxheWVyID0gIk5IRF9NYWpvcldhdGVyYm9kaWVzIix2ZXJib3NlID0gRkFMU0UscG9pbnREcm9wWiA9IFRSVUUpKSAlPiUKICAgICAgICBnQnVmZmVyKGJ5aWQ9VFJVRSwgd2lkdGg9MCkgJT4lICMgY2xlYW4gdXAgc2VsZi1pbnRlcnNlY3RpbmcgcG9seWdvbnMKICAgICAgICBzcFRyYW5zZm9ybShDUlNvYmogPSBjcnNfcHJvaikgICMgdHJhbnNmb3JtIHRoZSBwcm9qZWN0aW9uIHRvIG1hdGNoIHRoZSBwcm9qZWN0IHByb2plY3Rpb24Kd3RyX3NmIDwtICAKICAgICAgICB3dHJfc3AgJT4lIAogICAgICAgIHN0X2FzX3NmKCkgJT4lIAogICAgICAgIG1pc2NnaXM6OmNvZXJjZV90b19nZW9tKHN0X211bHRpcG9seWdvbikKCnd0cl9zZiAlPiUgCiAgICAgICAgc3RfaW50ZXJzZWN0cyh4ID0gc2VhX2NjZF9zZix5ID0gLikgJT4lIAogICAgICAgIHVubGlzdCh1c2UubmFtZXMgPSBGKSAlPiUgCiAgICAgICAgd3RyX3NmWy4sXSAlPiUgCiAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS93dHItc2YucmRzJykpCn0KCnd0cl9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vd3RyLXNmLnJkcycpKQoKc2hvd193dHIgPC0gZnVuY3Rpb24oKXsKICAgICAgICBteUxmbHRHcmV5KGRhdGEgPSBhcyh3dHJfc2YsJ1NwYXRpYWwnKSkgJT4lIAogICAgICAgICAgICAgICAgYWRkUG9seWdvbnMoY29sb3IgPSBibHVlLCBvcGFjaXR5ID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAuNSwgZmlsbENvbG9yID0gYmx1ZSxmaWxsT3BhY2l0eSA9IC41KSAgICAgICAgCn0KCnNob3dfd3RyKCkKCmBgYAoKIyMjIEtDIFRyYWN0cyBXaXRob3V0IChXZXN0ZXJuKSBXYXRlcmJvZGllcyAKYGBge3IgbWlzYy10cmFjdHMtY2NkLW5vLXd0cn0KCmlmKCFmaWxlLmV4aXN0cyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2Mtc2YucmRzJykpKXsKICAgICAgICB0cl9rY193dHJfc2YgJT4lIAogICAgICAgICAgICAgICAgZmlsdGVyKFRSQUNUQ0UgJSFpbiUgJzk5MDEwMCcpICU+JSAjIHJlbW92ZSB0aGUgUHVnZXQgU291bmQgdHJhY3QKICAgICAgICAgICAgICAgIG11dGF0ZShnZW9tZXRyeSA9IHN0X2RpZmZlcmVuY2UoZ2VvbWV0cnksc3RfdW5pb24od3RyX3NmKSkpICU+JSAKICAgICAgICAgICAgICAgIGNvZXJjZV90b19nZW9tKHN0X211bHRpcG9seWdvbikgJT4lIAogICAgICAgICAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS90ci1rYy1zZi5yZHMnKSkKfQoKdHJfa2Nfc2YgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3RyLWtjLXNmLnJkcycpKQoKc2hvd190cl9rY19zZiA8LSBmdW5jdGlvbigpewogICAgICAgIAogICAgICAgIHNlYWNjZCA8LSB0cl9rY19zZiAlPiUgZmlsdGVyKFNFQUNDRF9MR0wpCiAgICAgICAgb3RoZXJfa2MgPC0gdHJfa2Nfc2YgJT4lIGZpbHRlcighU0VBQ0NEX0xHTCkKICAgICAgICAKICAgICAgICBteUxmbHRHcmV5KCkgJT4lIAogICAgICAgIGFkZFBvbHlnb25zKGRhdGEgPSBhcyhzZWFjY2QsIlNwYXRpYWwiKSx3ZWlnaHQgPSAuNSxjb2xvciA9IGJsdWUsb3BhY2l0eSA9IDEsZmlsbENvbG9yID0gYmx1ZSxmaWxsT3BhY2l0eSA9IC41KSAlPiUgCiAgICAgICAgYWRkUG9seWdvbnMoZGF0YSA9IGFzKG90aGVyX2tjLCJTcGF0aWFsIiksd2VpZ2h0ID0gLjUsY29sb3IgPSBvcmFuZ2Usb3BhY2l0eSA9IDEsZmlsbENvbG9yID0gb3JhbmdlLGZpbGxPcGFjaXR5ID0gLjUpCn0KCnNob3dfdHJfa2Nfc2YoKQoKCgpgYGAKCg==